package com.bins.music.player.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class NeteaseWeapiEncryptor {

    // 静态初始化：注册 Bouncy Castle 提供者
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    // 固定密钥和 IV (来自逆向工程)
    private static final String SECRET_KEY = "0CoJUm6Qyw8W8jud";
    private static final String IV = "0102030405060708"; // 16 bytes

    // 固定的模数和指数 (RSA 公钥参数)
    private static final String MODULUS = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3688q1";
    private static final String EXPONENT = "010001"; // 16进制, 等于 65537

    /**
     * 执行 AES-128-CBC 加密
     */
    public static String aesEncrypt(String text, String key, String iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        
        byte[] encrypted = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 执行 RSA 加密 (OAEP with SHA-1 and MGF1)
     */
    public static String rsaEncrypt(byte[] dataToEncrypt) throws Exception {
        // 将16进制字符串转换为字节数组
        byte[] modulusBytes = hexStringToByteArray(MODULUS);
        byte[] exponentBytes = hexStringToByteArray(EXPONENT);

        // 创建公钥
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
        kpg.initialize(2048, new SecureRandom());
        KeyPair kp = kpg.generateKeyPair();


//        KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC"); // 使用 Bouncy Castle
//        RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(
//            new java.math.BigInteger(1, modulusBytes),
//            new java.math.BigInteger(1, exponentBytes)
//        );
//        java.security.PublicKey publicKey = keyFactory.generatePublic(pubSpec);
        java.security.PublicKey publicKey = kp.getPublic();

        // 加密
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding", "BC");
        // OAEP 参数：MD=SHA1, MGF1=SHA1
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(dataToEncrypt);
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * 辅助方法：将16进制字符串转为字节数组
     */
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    /**
     * 组装 weapi 请求参数并发送
     */
    public static void searchMusic(String keywords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        // 1. 构造原始数据对象
        Map<String, Object> rawData = new HashMap<>();
        rawData.put("s", keywords);
        rawData.put("type", 1); // 单曲搜索
        rawData.put("offset", 0);
        rawData.put("limit", 30);
        String text = mapper.writeValueAsString(rawData);

        // 2. 第一次加密: AES
        String params = aesEncrypt(text, SECRET_KEY, IV);
        System.out.println("AES params: " + params);

        // 3. 第二次加密: RSA
        // 注意: 这里传入的是 params 字符串的字节，不是 Base64 解码后的
        String encSecKey = rsaEncrypt(params.getBytes(StandardCharsets.UTF_8));
        System.out.println("RSA encSecKey: " + encSecKey);

        // 4. 组装 POST 数据
        Map<String, String> postData = new HashMap<>();
        postData.put("params", params);
        postData.put("encSecKey", encSecKey);
        String jsonPayload = mapper.writeValueAsString(postData);

        // 5. 发送 HTTP 请求
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpPost httpPost = new HttpPost("http://music.163.com/weapi/cloudsearch/get/web");
            
            // 设置 Headers
            httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            httpPost.setHeader("Referer", "https://music.163.com/");
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            // 设置请求体
            httpPost.setEntity(new StringEntity(jsonPayload, StandardCharsets.UTF_8));

            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    System.out.println("Response: " + result);
                    // 结果是加密的，通常还需要解密，但网易返回的weapi结果有时是明文JSON
                }
            }
        } finally {
            httpClient.close();
        }
    }

    // --- 主函数 ---
    public static void main(String[] args) {
        try {
            searchMusic("周杰伦");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


